/**
 * Copyright (C), 2011-2017  yhd.com
 * File Name: ObjectUtil.java
 * Encoding: UTF-8
 * Date: 17-4-18 上午10:02
 * History:
 */
package com.swak.frame.util;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.util.FastByteArrayOutputStream;

import com.alibaba.fastjson.JSON;
import com.swak.frame.logger.SwakLoggerFactory;

/**
 * ClassName: ObjectUtil.java
 * 
 * @Description: ObjectUtil
 * @author colley.ma
 * @date 2021年3月15日
 */
public final class ObjectUtil {

	private static final Logger logger = SwakLoggerFactory.getLogger(ObjectUtil.class);

	/**
	 * <p>
	 * 判断一组字符串中是否有 null 或者空值
	 * </p>
	 *
	 * @param arg0
	 * @param arg1
	 *
	 * @return 若一组字符串中的任何一个是 null 或者空值时返回 true，否则返回 false
	 *
	 */
	public static boolean isBlank(String arg0, String arg1, String... args) {
		if (StringUtils.isBlank(arg0) || StringUtils.isBlank(arg1)) {
			return true;
		}
		if (args == null) {
			return true;
		}
		for (int i = 0; i < args.length; i++) {
			if (StringUtils.isBlank(args[i])) {
				return true;
			}
		}

		return false;
	}

	/**
	 * <p>
	 * 判断数值对象是否为空
	 * </p>
	 */
	public static boolean isBlank(Number number) {
		return (number == null);
	}

	/**
	 * <p>
	 * 判断集合是否为 null 或者是空值
	 * </p>
	 */
	public static boolean isBlank(Collection<?> collection) {
		return ((collection == null) || (collection.size() == 0));
	}

	/**
	 * <p>
	 * 判断 Map 是否为 null 或者是空值
	 * </p>
	 */
	public static boolean isBlank(Map<?, ?> map) {
		return ((map == null) || (map.size() == 0));
	}

	/**
	 * <p>
	 * 判断对象数组是否为 null 或者是空
	 * </p>
	 */
	public static boolean isBlank(Object[] objs) {
		return ((objs == null) || (objs.length == 0));
	}

	/**
	 * Object转换成String
	 * 
	 * @author mayc
	 * @date 2014年4月23日
	 * @Time 上午10:01:18
	 *
	 * @param fvalue
	 * @return
	 */
	public static String obj2String(Object fvalue) {
		if (fvalue != null) {
			if (fvalue instanceof Date) {
				return DateTimeUtils.date2String((Date) fvalue);
			}
			if (fvalue instanceof Calendar) {
				return DateTimeUtils.calendar2String((Calendar) fvalue);
			}
			if (fvalue instanceof java.sql.Timestamp) {
				java.sql.Timestamp timestamp = (Timestamp) fvalue;
				return DateTimeUtils.date2String(timestamp);
			}
			if (fvalue instanceof java.sql.Date) {
				Date dateTemp = new Date(((java.sql.Date) fvalue).getTime());

				return DateTimeUtils.date2String(dateTemp);
			}
			if (fvalue instanceof String || fvalue instanceof Integer || fvalue instanceof Float
					|| fvalue instanceof Double || fvalue instanceof Long || fvalue instanceof Short
					|| fvalue instanceof Boolean) {
				return String.valueOf(fvalue);
			}
			return JSON.toJSONString(fvalue);
		}
		return "";
	}

	public static boolean isArray(Object o) {
		return o.getClass().isArray();
	}

	public static boolean isNull(Object obj) {
		return obj == null;
	}

	public static boolean nonNull(Object obj) {
		return obj != null;
	}

	public static boolean nonNull(Object[] os) {
		if ((null == os) || (os.length == 0) || (os[0] == null)) {
			return false;
		} else {
			return true;
		}
	}

	public static boolean nonEmpty(String s) {
		if ((null == s) || "".equals(s.trim())) {
			return false;
		} else {
			return true;
		}
	}

	// 判断是否是接口的实现类路径
	public static boolean isInterfaceImpl(Object o, String implpath, Class<?> inter) throws ClassNotFoundException {
		if (null != implpath) {
			return inter.isAssignableFrom(o.getClass().getClassLoader().loadClass(implpath));
		}

		return false;
	}

	public static boolean isInterfaceImpl(Class<?> impl, Class<?> inter) {
		return inter.isAssignableFrom(impl);
	}

	public static boolean isInstance(Class<?> c, Object o) {
		if (c.isInstance(o)) {
			return true;
		}

		return false;
	}

	public static Object loadInstance(String clazz)
			throws InstantiationException, IllegalAccessException, ClassNotFoundException {
		return ObjectUtil.class.getClassLoader().loadClass(clazz.trim()).newInstance();
	}

	public static Object loadInstance(Class<?> c) throws InstantiationException, IllegalAccessException {
		return c.newInstance();
	}

	public static Class<?> loadClass(String path) throws ClassNotFoundException {
		return ObjectUtil.class.getClassLoader().loadClass(path);
	}

	public static boolean isTrue(String s) {
		if (null == s) {
			return false;
		}

		if (s.equalsIgnoreCase("Y") || s.equalsIgnoreCase("YES") || s.equalsIgnoreCase("TRUE")
				|| s.equalsIgnoreCase("T")) {
			return true;
		}

		return false;
	}

	public static <T> Field[] getFields(Class<T> t, List<Field> fields) {
		Field[] cfields = t.getDeclaredFields();

		for (Field f : cfields) {
			if (f != null) {
				fields.add(f);
			}
		}

		Class<?> upsercls = t.getSuperclass();

		if (upsercls != Object.class) {
			getFields(upsercls, fields);
		}

		return fields.toArray(new Field[fields.size()]);
	}

	private static <T> Field[] getFields(T t, List<Field> fields) {
		return getFields(t.getClass(), fields);
	}

	public static <T> Map<String, Object> getProp2Map(T t) {
		Field[] fields = getFields(t, new ArrayList<Field>());
		Map<String, Object> maps = new HashMap<String, Object>();

		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			String name = field.getName();

			try {
				Object fvalue = null;
				Class<?> type = field.getType();

				if (type == InputStream.class) {
					fvalue = null;
				} else if (type == List.class) {
					fvalue = null;
				} else if (type == Map.class) {
					fvalue = null;
				} else {
					field.setAccessible(true);
					fvalue = field.get(t);

					String strval = obj2String(fvalue);

					if (strval != null) {
						maps.put(name, strval);
					}
				}
			} catch (Exception e) {
			}
		}

		return maps;
	}

	/**
	 * 判断所有参数是否必填
	 * 
	 * @param objects
	 * @return
	 */
	public static boolean isMustNotEmpty(Object... objects) {
		if (objects == null) {
			return false;
		}
		for (Object object : objects) {
			if (!nonNull(object)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 克隆对象<br>
	 * 如果对象实现Cloneable接口，调用其clone方法<br>
	 * 如果实现Serializable接口，执行深度克隆<br>
	 * 否则返回<code>null</code>
	 *
	 * @param <T> 对象类型
	 * @param obj 被克隆对象
	 * @return 克隆后的对象
	 * @throws InvocationTargetException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	@SuppressWarnings("unchecked")
	public static <T> T clone(T obj) throws Exception {
		T result = cloneArray(obj);
		if (null == result) {
			if (obj instanceof Cloneable) {
				Method method = getCloneMethod(obj.getClass());
				if (method != null) {
					method.setAccessible(true);
					result = (T) method.invoke(obj);
				}
			} else {
				result = cloneByStream(obj);
			}
		}
		return result;
	}

	private static Method getCloneMethod(Class<?> claszz) {
		Method method = null;
		try {
			method = claszz.getDeclaredMethod("clone");
		} catch (NoSuchMethodException e) {
			try {
				method = claszz.getMethod("clone");
			} catch (Exception e1) {
				logger.error(e.getMessage());
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return method;
	}

	/**
	 * 克隆数组
	 *
	 * @param <T>   数组元素类型
	 * @param array 被克隆的数组
	 * @return 新数组
	 */
	public static <T> T[] clone(T[] array) {
		if (array == null) {
			return null;
		}
		return array.clone();
	}

	/**
	 * 克隆数组，如果非数组返回<code>null</code>
	 *
	 * @param <T> 数组元素类型
	 * @param obj 数组对象
	 * @return 克隆后的数组对象
	 */
	@SuppressWarnings("unchecked")
	public static <T> T cloneArray(final T obj) {
		if (null == obj) {
			return null;
		}
		if (isArray(obj)) {
			final Object result;
			final Class<?> componentType = obj.getClass().getComponentType();
			if (componentType.isPrimitive()) {// 原始类型
				int length = Array.getLength(obj);
				result = Array.newInstance(componentType, length);
				while (length-- > 0) {
					Array.set(result, length, Array.get(obj, length));
				}
			} else {
				result = ((Object[]) obj).clone();
			}
			return (T) result;
		}
		return null;
	}

	/**
	 * 返回克隆后的对象，如果克隆失败，返回原对象
	 *
	 * @param <T> 对象类型
	 * @param obj 对象
	 * @return 克隆后或原对象
	 */
	public static <T> T cloneIfPossible(final T obj) {
		T clone = null;
		try {
			clone = clone(obj);
		} catch (Exception e) {
			// pass
		}
		return clone == null ? obj : clone;
	}

	/**
	 * 序列化后拷贝流的方式克隆<br>
	 * 对象必须实现Serializable接口
	 *
	 * @param <T> 对象类型
	 * @param obj 被克隆对象
	 * @return 克隆后的对象
	 * @throws UtilException IO异常和ClassNotFoundException封装
	 */
	@SuppressWarnings("unchecked")
	public static <T> T cloneByStream(T obj) {
		if (false == (obj instanceof Serializable)) {
			return null;
		}
		final FastByteArrayOutputStream byteOut = new FastByteArrayOutputStream();
		ObjectOutputStream out = null;
		try {
			out = new ObjectOutputStream(byteOut);
			out.writeObject(obj);
			out.flush();
			final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()));
			return (T) in.readObject();
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			IOUtil.close(out);
		}
	}

	/**
	 * 将新元素插入到到已有数组中的某个位置<br>
	 * 添加新元素会生成一个新的数组，不影响原数组<br>
	 * 如果插入位置为为负数，从原数组从后向前计数，若大于原数组长度，则空白处用null填充
	 *
	 * @param <T>         数组元素类型
	 * @param buffer      已有数组
	 * @param index       插入位置，此位置为对应此位置元素之前的空档
	 * @param newElements 新元素
	 * @return 新数组
	 * @since 4.0.8
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] insert(T[] buffer, int index, T... newElements) {
		return (T[]) insert((Object) buffer, index, newElements);
	}

	/**
	 * 将新元素插入到到已有数组中的某个位置<br>
	 * 添加新元素会生成一个新的数组，不影响原数组<br>
	 * 如果插入位置为为负数，从原数组从后向前计数，若大于原数组长度，则空白处用null填充
	 *
	 * @param <T>         数组元素类型
	 * @param array       已有数组
	 * @param index       插入位置，此位置为对应此位置元素之前的空档
	 * @param newElements 新元素
	 * @return 新数组
	 * @since 4.0.8
	 */
	public static <T> Object insert(Object array, int index, @SuppressWarnings("unchecked") T... newElements) {
		if (!nonNull(newElements)) {
			return array;
		}
		if (!nonNull(array)) {
			return newElements;
		}

		final int len = Array.getLength(array);
		if (index < 0) {
			index = (index % len) + len;
		}

		final T[] result = newArray(array.getClass().getComponentType(), Math.max(len, index) + newElements.length);
		System.arraycopy(array, 0, result, 0, Math.min(len, index));
		System.arraycopy(newElements, 0, result, index, newElements.length);
		if (index < len) {
			System.arraycopy(array, index, result, index + newElements.length, len - index);
		}
		return result;
	}

	/**
	 * 新建一个空数组
	 *
	 * @param <T>           数组元素类型
	 * @param componentType 元素类型
	 * @param newSize       大小
	 * @return 空数组
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] newArray(Class<?> componentType, int newSize) {
		return (T[]) Array.newInstance(componentType, newSize);
	}

	/**
	 * 将新元素添加到已有数组中<br>
	 * 添加新元素会生成一个新的数组，不影响原数组
	 *
	 * @param <T>         数组元素类型
	 * @param buffer      已有数组
	 * @param newElements 新元素
	 * @return 新数组
	 */
	@SafeVarargs
	public static <T> T[] append(T[] buffer, T... newElements) {
		if (!nonNull(buffer)) {
			return newElements;
		}
		return insert(buffer, buffer.length, newElements);
	}

	/**
	 * 将新元素添加到已有数组中<br>
	 * 添加新元素会生成一个新的数组，不影响原数组
	 *
	 * @param <T>         数组元素类型
	 * @param array       已有数组
	 * @param newElements 新元素
	 * @return 新数组
	 */
	@SafeVarargs
	public static <T> Object append(Object array, T... newElements) {
		if (!nonNull(array)) {
			return newElements;
		}
		return insert(array, Array.getLength(array), newElements);
	}
}
